
package com.naza.rpc.netty;

import com.naza.rpc.core.Modular;
import com.naza.rpc.core.ModuleInvoker;
import com.naza.rpc.core.ModuleProvider;
import com.naza.rpc.core.RpcSystemConfig;
import com.naza.rpc.spring.BeanFactoryUtils;
import com.naza.rpc.model.RpcRequest;
import com.naza.rpc.model.RpcResponse;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.NameMatchMethodPointcutAdvisor;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Map;
import java.util.concurrent.Callable;

/**
 * RPC 服务端消息接收处理顶层
 * 
 * @author yl
 */
public abstract class AbstractMessageRecvInitializeTask implements Callable<Boolean> {
    protected RpcRequest request = null;

    protected RpcResponse response = null;

    protected Map<String, Object> handlerMap = null;

    protected static final String METHOD_MAPPED_NAME = "invoke";

    protected boolean returnNotNull = true;

    protected long invokeTimespan;

    protected Modular modular = BeanFactoryUtils.getBean("modular");

    public AbstractMessageRecvInitializeTask(RpcRequest request, RpcResponse response,
                                             Map<String, Object> handlerMap) {
        this.request = request;
        this.response = response;
        this.handlerMap = handlerMap;
    }

    //服务端真正执行业务service调用的地方
    @Override
    public Boolean call() {
        try {
            // 获取信号量
            acquire();
            response.setMessageId(request.getMessageId());
            //调用前处理
            injectInvoke();
            Object result = reflect(request);
            boolean isInvokeSucc = ((returnNotNull && result != null) || !returnNotNull);
            if (isInvokeSucc) {
                //调用成功
                response.setResult(result);
                response.setError("");
                response.setReturnNotNull(returnNotNull);
                injectSuccInvoke(invokeTimespan);
            } else {
                System.err.println(RpcSystemConfig.FILTER_RESPONSE_MSG);
                response.setResult(null);
                response.setError(RpcSystemConfig.FILTER_RESPONSE_MSG);
                injectFilterInvoke();
            }
            return Boolean.TRUE;
        } catch (Throwable t) {
            //调用失败
            response.setError(getStackTrace(t));
            t.printStackTrace();
            System.err.printf("RPC Server invoke error!\n");
            injectFailInvoke(t);
            return Boolean.FALSE;
        } finally {
            release();
        }
    }

    /**
     * 反射调用
     * @param mi
     * @param request
     * @return
     * @throws Throwable
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    private Object invoke(MethodInvoker mi, RpcRequest request) throws Throwable {
        if (modular != null) {
            ModuleProvider provider = modular.invoke(new ModuleInvoker() {

                @Override
                public Class getInterface() {
                    return mi.getClass().getInterfaces()[0];
                }

                @Override
                public Object invoke(RpcRequest request) throws Throwable {
                    return mi.invoke(request);
                }

                @Override
                public void destroy() {

                }
            }, request);
            return provider.getInvoker().invoke(request);
        } else {
            return mi.invoke(request);
        }
    }

    /**
     * 反射调用业务service
     * @param request
     * @return
     * @throws Throwable
     */
    private Object reflect(RpcRequest request) throws Throwable {
        ProxyFactory weaver = new ProxyFactory(new MethodInvoker());
        NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor();
        advisor.setMappedName(METHOD_MAPPED_NAME);
        advisor.setAdvice(new MethodProxyAdvisor(handlerMap));
        weaver.addAdvisor(advisor);
        MethodInvoker mi = (MethodInvoker) weaver.getProxy();
        //反射调用
        Object obj = invoke(mi, request);
        //获取反射调用的执行时间
        invokeTimespan = mi.getInvokeTimespan();
        setReturnNotNull(((MethodProxyAdvisor) advisor.getAdvice()).isReturnNotNull());
        return obj;
    }

    public String getStackTrace(Throwable ex) {
        StringWriter buf = new StringWriter();
        ex.printStackTrace(new PrintWriter(buf));

        return buf.toString();
    }

    public boolean isReturnNotNull() {
        return returnNotNull;
    }

    public void setReturnNotNull(boolean returnNotNull) {
        this.returnNotNull = returnNotNull;
    }

    public RpcResponse getResponse() {
        return response;
    }

    public RpcRequest getRequest() {
        return request;
    }

    public void setRequest(RpcRequest request) {
        this.request = request;
    }

    protected abstract void injectInvoke();

    /**
     * 调用成功后处理
     * @param invokeTimespan 调用耗时
     */
    protected abstract void injectSuccInvoke(long invokeTimespan);

    /**
     * 调用失败后处理
     * @param error 错误
     */
    protected abstract void injectFailInvoke(Throwable error);

    protected abstract void injectFilterInvoke();

    /**
     * 获取信号量许可
     */
    protected abstract void acquire();

    /**
     * 释放信号量
     */
    protected abstract void release();
}
